#include "../include/Socket.h"

Socket::Socket() : _fd(DefaultFD) {}

Socket::Socket(int fd) : _fd(fd) {}

Socket::~Socket() { Close(); }

int Socket::getFd() { return _fd; }

bool Socket::CreateSocket()
{
    _fd = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
    if (_fd < 0)
    {
        ERR_LOG("套接字创建失败\n");
        return false;
    }
    return true;
}

bool Socket::BindAddress(const std::string &addr, uint16_t port)
{
    struct sockaddr_in addr1;
    addr1.sin_family = AF_INET;
    addr1.sin_port = htons(port);
    addr1.sin_addr.s_addr = inet_addr(addr.c_str());
    socklen_t len = sizeof(struct sockaddr_in);
    int ret = bind(_fd, ((struct sockaddr *)&addr1), len);
    if (ret < 0)
    {
        ERR_LOG("绑定地址失败\n");
        return false;
    }
    return true;
}

bool Socket::Listen(int backlog)
{
    int ret = listen(_fd, backlog);
    if (ret < 0)
    {
        ERR_LOG("监听套接字失败\n");
        return false;
    }
    return true;
}

bool Socket::ConnServer(const std::string &addr, uint16_t port)
{
    struct sockaddr_in addr1;
    addr1.sin_family = AF_INET;
    addr1.sin_port = htons(port);
    addr1.sin_addr.s_addr = inet_addr(addr.c_str());
    socklen_t len = sizeof(struct sockaddr_in);
    int ret = connect(_fd, ((struct sockaddr *)&addr1), len);
    if (ret < 0)
    {
        ERR_LOG("连接服务器失败\n");
        return false;
    }
    return true;
}

int Socket::Accept()
{
    while (true)
    {
#ifdef SOCK_CLOEXEC
        int newfd = accept4(_fd, nullptr, nullptr, SOCK_NONBLOCK | SOCK_CLOEXEC);
#else
        int newfd = accept(_fd, nullptr, nullptr);
#endif
        if (newfd >= 0)
        {
#ifndef SOCK_CLOEXEC
            int flags = fcntl(newfd, F_GETFL, 0);
            if (flags >= 0)
            {
                fcntl(newfd, F_SETFL, flags | O_NONBLOCK);
            }
#endif
            int opt = 1;
            setsockopt(newfd, IPPROTO_TCP, TCP_NODELAY, &opt, sizeof(opt));
            return newfd;
        }

        if (errno == EINTR)
        {
            continue;
        }
        if (errno == EAGAIN || errno == EWOULDBLOCK)
        {
            return DefaultFD;
        }

        if (errno == EMFILE || errno == ENFILE)
        {
            ERR_LOG("获取新连接失败: 描述符耗尽 (%s)\n", strerror(errno));
        }
        else
        {
            ERR_LOG("获取新连接失败: %s\n", strerror(errno));
        }
        return DefaultFD;
    }
}

ssize_t Socket::Recv(void *buf, size_t len, int flag)
{
    while (true)
    {
        ssize_t n = recv(_fd, buf, len, flag);
        if (n > 0)
        {
            return n;
        }
        if (n == 0)
        {
            return 0;
        }

        if (errno == EINTR)
        {
            continue;
        }
        if (errno == EAGAIN || errno == EWOULDBLOCK)
        {
            return SOCKET_EAGAIN;
        }

        ERR_LOG("接收出错: %s", strerror(errno));
        return -1;
    }
}

ssize_t Socket::NonBlockRecv(void *buf, size_t len)
{
    return Recv(buf, len, MSG_DONTWAIT);
}

ssize_t Socket::Send(const void *buf, size_t len, int flag)
{
    while (true)
    {
        ssize_t n = send(_fd, buf, len, flag);
        if (n >= 0)
        {
            return n;
        }
        if (errno == EINTR)
        {
            continue;
        }
        if (errno == EAGAIN || errno == EWOULDBLOCK)
        {
            return SOCKET_EAGAIN;
        }

        ERR_LOG("发送失败: %s", strerror(errno));
        return -1;
    }
}

ssize_t Socket::NonBlockSend(void *buf, size_t len)
{
    return Send(buf, len, MSG_DONTWAIT);
}

void Socket::Close()
{
    if (_fd != -1)
    {
        ::close(_fd);
        _fd = -1;
    }
}

bool Socket::CreateServerConn(uint16_t port, const std::string &addr)
{
    bool sock = CreateSocket();
    if (!sock)
        return false;

    // Must set socket options before binding
    ReuseAddress();
    NonBlock();
    SetTcpNoDelay();

    bool bid = BindAddress(addr, port);
    if (!bid)
        return false;

    bool lis = Listen();
    if (!lis)
        return false;

    return true;
}

bool Socket::CreateClientConn(uint16_t port, const std::string &addr)
{
    bool sock = CreateSocket();
    if (!sock)
        return false;

    bool conn = ConnServer(addr, port);
    if (!conn)
        return false;
    return true;
}

void Socket::ReuseAddress()
{
    int opt = 1;
    int ret = setsockopt(_fd, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(opt));
    if (ret < 0)
    {
        ERR_LOG("设置地址重用失败\n");
        return;
    }
    opt = 1;
    int ret1 = setsockopt(_fd, SOL_SOCKET, SO_REUSEPORT, &opt, sizeof(opt));
    if (ret1 < 0)
    {
        ERR_LOG("设置端口重用失败\n");
        return;
    }
}

void Socket::NonBlock()
{
    int flags = fcntl(_fd, F_GETFL, 0);
    if (flags < 0)
    {
        ERR_LOG("获取套接字标志失败\n");
        return;
    }
    int ret = fcntl(_fd, F_SETFL, flags | O_NONBLOCK);
    if (ret < 0)
    {
        ERR_LOG("设置套接字为非阻塞失败\n");
        return;
    }
}

void Socket::SetTcpNoDelay()
{
    int opt = 1;
    int ret = setsockopt(_fd, IPPROTO_TCP, TCP_NODELAY, &opt, sizeof(opt));
    if (ret < 0)
    {
        ERR_LOG("设置TCP_NODELAY失败\n");
    }
}

void Socket::SetKeepAlive()
{
    int opt = 1;
    int ret = setsockopt(_fd, SOL_SOCKET, SO_KEEPALIVE, &opt, sizeof(opt));
    if (ret < 0)
    {
        ERR_LOG("设置SO_KEEPALIVE失败\n");
        return;
    }

    int keepidle = 60;
    int keepinterval = 5;
    int keepcount = 3;

    setsockopt(_fd, IPPROTO_TCP, TCP_KEEPIDLE, &keepidle, sizeof(keepidle));
    setsockopt(_fd, IPPROTO_TCP, TCP_KEEPINTVL, &keepinterval, sizeof(keepinterval));
    setsockopt(_fd, IPPROTO_TCP, TCP_KEEPCNT, &keepcount, sizeof(keepcount));
}
